home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CHESS.PAK / TALK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  12.7 KB  |  561 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1993 by Borland International
  3. //----------------------------------------------------------------------------
  4. #include <owl/pch.h>
  5. #include <owl/defs.h>
  6. #include <fstream.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <math.h>
  11. #include <dos.h>
  12. #include <time.h>
  13. #include <ctype.h>
  14. #include "wchess.h"
  15. #include "wcdefs.h"
  16. #include "externs.h"
  17.  
  18. //
  19. //  Global declarations
  20. //
  21. char *INIFile = "wchess.ini";
  22. BOOL InLibrary;      // True if program is in the opening library
  23. BOOL MultiMove,      // True if multimove mode
  24.      AutoPlay,       // True if AutoPlay mode
  25.      SingleStep;     // Single Step mode, used for debugging purposes
  26. LEVELTYPE Level;
  27. double AverageTime = 5.0;
  28. PIECETYPE Pieces[8]  = { rook, knight, bishop, queen,
  29.                          king, bishop, knight, rook};
  30. BOOL MaxLevel;
  31. BOOL Turned;
  32. BOOL UseLib;
  33. LIBTYPE Openings;
  34. COLORTYPE ProgramColor;
  35. int MoveNo;
  36. int PVTable[2][7][0x78];
  37. MOVETYPE PlayerMove;
  38. BOOL Logging;
  39. NODEVAL Nodes;             // Number of analysed nodes
  40. CLOCKTYPE ChessClock;
  41. extern int LegalMoves;
  42. LINETYPE HintLine;            //  suggested hint line
  43. MAXTYPE HintEvalu;            //  Evaluation for hintline
  44. enum ANALYSISCONTROL { Start, Return, Continue };
  45.  
  46. int OpCount, LibNo;
  47.  
  48. static DEPTHTYPE LibDepth;
  49. static BOOL Found;
  50. static DEPTHTYPE dep;
  51.  
  52. ofstream *OutputFile;
  53.  
  54. enum CONTROLVAR { readmove, checkmove, gamemove};
  55. static CONTROLVAR Control;
  56.  
  57.  
  58. void
  59. InsertPiece(PIECETYPE p, COLORTYPE c, SQUARETYPE sq)
  60. {
  61.   Board[sq].piece = p;
  62.   Board[sq].color = c;
  63. }
  64.  
  65.  
  66. void
  67. ClearPVTable()
  68. {
  69.   COLORTYPE  color;
  70.   PIECETYPE  piece;
  71.   SQUARETYPE square;
  72.  
  73.   for (color = white; color <= black; ((int)color)++)
  74.     for (piece = king; piece <= pawn; ((int)piece)++)
  75.       for (square = 0; square <= 0x77; square++)
  76.         PVTable[color][piece][square] = 0;
  77. }
  78.  
  79. void
  80. ResetGame()
  81. {
  82.   ClearBoard();
  83.   Running = FALSE;
  84.   for (int i = 0; i < 8; i++) {
  85.     InsertPiece(Pieces[i], white, i);
  86.     InsertPiece(pawn, white, i + 0x10);
  87.     InsertPiece(pawn, black, i + 0x60);
  88.     InsertPiece(Pieces[i], black, i + 0x70);
  89.   }
  90.   CalcPieceTab();
  91.   Player = white;
  92.   ClearDisplay();
  93.   InitDisplay();
  94.   ColorToPlay(Player);
  95.   Opponent = black;
  96. }
  97.  
  98.  
  99. void
  100. NewGame()
  101. {
  102.   SingleStep = InLibrary = FALSE;
  103.   GameOver = FALSE;
  104.   ResetGame();
  105.   PrintCurLevel();
  106.   ResetMoves();
  107.   if (!*Openings)
  108.     UseLib = 0;
  109.   else
  110.     UseLib = 200;
  111.   MovTab[-1].content = king;
  112.   InitChessTime();
  113.   ProgramColor = white;
  114.   MoveNo = 0;
  115.   ClearHint();
  116.   ClearPVTable();
  117.   PlayerMove = ZeroMove;
  118.   if (Logging && !AutoPlay)
  119.     *OutputFile << "\n No  Player Program    Hint    Value Level     Nodes  Time\n";
  120.   InitNode(&Nodes);
  121.   ChessClock.totaltime = 0.0;
  122.   Control = (AutoPlay) ? gamemove : readmove;
  123. }
  124.  
  125. void
  126. ResetNewPos()
  127. {
  128.   ResetMoves();
  129.   CalcPieceTab();
  130.   UseLib = FALSE;
  131.   Running = FALSE;
  132.   ClearHint();
  133. }
  134.  
  135. void
  136. ResetOpening()
  137. {
  138.   const char *libfilename = "opening.mvs";
  139.   ifstream fin(libfilename, ios::in | ios::binary);
  140.  
  141.   if (!fin) {
  142.     MessageBox(0,"Cannot find Openings Library", "Error", MB_ICONHAND | MB_OK);
  143.     Openings = new unsigned char;
  144.     *Openings = 0;
  145.     return;
  146.   }
  147.   Openings = new unsigned char[32000];
  148.   fin.read(Openings, 32000);
  149.   fin.close();
  150.   *Openings = 0xFF;
  151. }
  152.  
  153. static void
  154. StartUp()
  155. {
  156.   randomize();
  157.  
  158.   Level = (LEVELTYPE)GetPrivateProfileInt("WCHESS", "Level", (int)easygame, INIFile);
  159.  
  160.   if (GetPrivateProfileString("WCHESS", "AverageTime", "5.0", buf, 80, INIFile))
  161.     sscanf(buf, "%lf", &AverageTime);
  162.  
  163.   if (GetPrivateProfileString("WCHESS", "WhiteSquare", "", buf, 80, INIFile))
  164.     sscanf(buf, "%ld", &WhiteSquareColor);
  165.  
  166.   if (GetPrivateProfileString("WCHESS", "BlackSquare", "", buf, 80, INIFile))
  167.     sscanf(buf, "%ld", &BlackSquareColor);
  168.  
  169.   MaxLevel = (BYTE)GetPrivateProfileInt("WCHESS", "MaxLevel", MAXPLY, INIFile);
  170.   SoundOn = (BOOL)GetPrivateProfileInt("WCHESS", "SoundOn", 1, INIFile);
  171.  
  172.   if (!SoundOn)  // defaults to checked at startup
  173.     CheckMenuItem(MainMenu, IDM_SOUND, MF_UNCHECKED);
  174.   CalcAttackTab();
  175.   MultiMove = FALSE;
  176.   AutoPlay = FALSE;
  177.   Turned = FALSE;
  178.   ResetOpening();
  179.  
  180.   OutputFile = new ofstream("Chess.log");
  181.   if (!OutputFile) {
  182.     MessageBox(0, "Unable to open log file.\nLogging disabled", "OWL Chess", MB_OK | MB_ICONEXCLAMATION);
  183.     Logging = FALSE;
  184.  
  185.   } else {
  186.     *OutputFile << endl;
  187.     *OutputFile << "      OWL CHESS by Borland International\n";
  188.     *OutputFile << "      ==================================\n" << endl;
  189.   }
  190. }
  191.  
  192. const UNPLAYMARK = 0x3f;
  193.  
  194. //
  195. //  Sets libno to the previous move in the block
  196. //
  197. void
  198. PreviousLibNo()
  199. {
  200.   int n = 0;
  201.   do {
  202.    LibNo--;
  203.    if (Openings[LibNo] >= 128)
  204.      n++;
  205.    if (Openings[LibNo] & 64)
  206.      n--;
  207.   } while (n);
  208. }
  209.  
  210. //
  211. //  Set libno to the first move in the block
  212. //
  213. void
  214. FirstLibNo()
  215. {
  216.   while (!(Openings[LibNo - 1] & 64))
  217.     PreviousLibNo();
  218. }
  219.  
  220. //
  221. //  set libno to the next move in the block.  Unplayable
  222. //  moves are skipped if skip is set
  223. //
  224. void
  225. NextLibNo(short skip)
  226. {
  227.   if (Openings[LibNo] >= 128)
  228.     FirstLibNo();
  229.   else {
  230.     int n = 0;
  231.     do {
  232.       if (Openings[LibNo] & 64)
  233.         n++;
  234.       if (Openings[LibNo] >= 128)
  235.         n--;
  236.       LibNo++;
  237.     } while (n);
  238.     if (skip && (Openings[LibNo] == UNPLAYMARK))
  239.       FirstLibNo();
  240.   }
  241. }
  242.  
  243. //
  244. //  find the node corresponding to the correct block
  245. //
  246. static void
  247. FindNode()
  248. {
  249.   LibNo++;
  250.   if (Depth > LibDepth) {
  251.     Found = TRUE;
  252.     return;
  253.   }
  254.   OpCount = -1;
  255.   InitMovGen();
  256.   do {
  257.     OpCount++;
  258.     MovGen();
  259.   } while (Next.movpiece != empty && !EqMove(&Next, &MovTab[Depth]));
  260.   if (Next.movpiece != empty) {
  261.     while ((Openings[LibNo] & 63) != OpCount && Openings[LibNo] < 128)
  262.       NextLibNo(0);
  263.     if ((Openings[LibNo] & 127) == 64 + OpCount) {
  264.       MakeMove(&MovTab[Depth]);
  265.       FindNode();
  266.       TakeBackMove(&MovTab[Depth-1]);
  267.     }
  268.   }
  269. }
  270.  
  271. //
  272. //  Set LibNo to the block corresponding to the position
  273. //
  274. void
  275. CalcLibNo()
  276. {
  277.   LibNo = 0;
  278.   if (MoveNo < UseLib) {
  279.     LibDepth = Depth;
  280.     while (MovTab[Depth].movpiece != empty)
  281.       TakeBackMove(&MovTab[Depth]);
  282.     Found = FALSE;
  283.     if (MovTab[Depth].content == king) {
  284.       Depth++;
  285.       FindNode();
  286.       Depth--;
  287.     }
  288.     while(Depth < LibDepth)
  289.       MakeMove(&MovTab[Depth + 1]);
  290.     if (Found)
  291.       UseLib = 200;
  292.     else {
  293.       UseLib = MoveNo;
  294.       LibNo = 0;
  295.     }
  296.   }
  297. }
  298.  
  299. //
  300. //  find an opening move from the library
  301. //
  302. static void
  303. FindOpeningMove()
  304. {
  305.   const unsigned char weight[7] = {7, 10, 12, 13, 14, 15, 16};
  306.  
  307.   unsigned char r = (unsigned char)random(16);   //  calculate weighted random number in 0..16
  308.   unsigned char p = 0;
  309.   while (r >= weight[p])
  310.     p++;
  311.   for (unsigned char countp = 1; countp <= p; countp++)  // find corresponding node
  312.     NextLibNo(1);
  313.   OpCount = Openings[LibNo] & 63;  //  generate the move
  314.   InitMovGen();
  315.   for (unsigned char cnt = 0; cnt <= OpCount; cnt++)
  316.     MovGen();
  317.  
  318.   // store the move in mainline
  319.   MainLine[0] = Next;
  320.   MainLine[1] = ZeroMove;
  321.   MainEvalu = 0;
  322.   MaxDepth = 0;
  323.   LegalMoves = 0;
  324.   InitNode(&Nodes);
  325. }
  326.  
  327. void
  328. OutputNode(NODEVAL* nodes)
  329. {
  330.   double nodereal;
  331.   if (!Logging)
  332.     return;
  333.   char buf[20];
  334.   nodereal = nodes->nodebase * MAXINT + nodes->nodeoffset;
  335.   sprintf(buf, "%12.1f", nodereal);
  336.   *OutputFile << buf;
  337. }
  338.  
  339. static void ThinkAwhile();
  340. void StartMove();
  341.  
  342. void
  343. ReturnAnalysis()
  344. {
  345.   int myx;
  346.   char str[8];
  347.   char buf[40];
  348.  
  349.   MovTab[0] = MainLine[0];   //  copy the MainLine to HintLine
  350.   for (myx = 0; myx < MAXPLY; myx++)
  351.     HintLine[myx] = MainLine[myx];
  352.   dep = MAXPLY;
  353.   HintEvalu = MainEvalu;
  354.   if (MovTab[0].movpiece == empty) {
  355.     HintLine[0] = ZeroMove;   //  No possible move
  356.     if (AutoPlay) {
  357.       NewGame();
  358.       PrintBoard();
  359.       StartMove();
  360.     }
  361.     return;
  362.   }
  363.  
  364. //   FlashMove(&MovTab[Depth+1]);  //  flash and perform the move
  365.   DoSlideMove(MovTab[Depth+1]);
  366.   EnterMove(&MovTab[Depth+1]);
  367.   if (SoundOn)
  368.     MessageBeep(0);
  369.   StoreMoves();
  370.   if (Logging && !AutoPlay) {
  371.     sprintf(buf, "%3d. ",(MoveNo+1) / 2);
  372.     *OutputFile << buf;
  373.     strcpy(str, MoveStr(&MovTab[0]));
  374.     if ((PlayerMove.movpiece == empty) && (Opponent == white))
  375.       sprintf(buf, "%8.8s ", str);
  376.     else
  377.       sprintf(buf, "%s%8.8s",MoveStr(&PlayerMove), str);
  378.     *OutputFile << buf;
  379.     sprintf(buf, "  (%s)%9.2f%3d:%2d", MoveStr(&MainLine[1]),
  380.             MainEvalu / 256.0, MaxDepth, LegalMoves);
  381.     *OutputFile << buf;
  382.     OutputNode(&Nodes);
  383.     sprintf(buf, "%8.1lf\n", ChessClock.totaltime);
  384.     *OutputFile << buf;
  385.   }
  386.   PlayerMove = ZeroMove;
  387.   ColorToPlay(Player);
  388.   if (AutoPlay) {
  389.     if (MoveNo >= 120 || FiftyMoveCnt() >= 100 || Repetition(0) >= 3 || MainEvalu <= -0x880) {
  390.       NewGame();
  391.       PrintBoard();
  392.     }
  393.     StartMove();
  394.     return;
  395.   }
  396.   if (Level != easygame && !GameOver)
  397.     ThinkAwhile();
  398. }
  399.  
  400. //
  401. //  Perform analysis in the opponents time of reflection.
  402. //  The program assumes that the opponent will perform the
  403. //  Hint move, and starts analysing on it for a counter move
  404. //
  405. static void
  406. ThinkAwhile()
  407. {
  408.   extern HCURSOR hArrowCursor;
  409.  
  410.   SetClassWindowCursor(hWndMain, hArrowCursor);
  411.   SetMenu(hWndMain, MainMenu);
  412.  
  413.   if (HintLine[0].movpiece == empty || MultiMove)
  414.     return;
  415.   Analysis = FALSE;
  416.   Opan = TRUE;
  417.   AdjustMoves();      //  Setup surroundings as if the
  418.   MovTab[Depth+1] = HintLine[0];  //  Opponent had performed
  419.   MakeMove(&MovTab[Depth+1]);    //  The hint move
  420.   StoreMoves();
  421.   AdjustMoves();
  422.   Depth = 0;      //  analyse until something is entered from by
  423.   FindMove(MaxLevel); //  the user
  424.   Depth = -1;
  425.   Opan = FALSE;
  426.   if (Analysis) {      //  If the Opponent did make the Hint move then go and
  427.     ReturnAnalysis();   //  perform the counter move
  428.     return;
  429.   }
  430.   TakeBackMove(&MovTab[Depth]);  //  restore the surroundings
  431.   if (GotValidMove) {
  432.     AdjustMoves();
  433.     EnterKeyMove();
  434.     StoreMoves();
  435.     SetMenu(hWndMain, ThinkMenu);
  436.     SetClassWindowCursor(hWndMain, hWaitCursor);
  437.   }
  438.   return;
  439. }
  440.  
  441. void
  442. StartMove()
  443. {
  444.   MSG msg;
  445.   StartAnalysis();
  446.   AdjustMoves();
  447.   CalcLibNo();      //  Try to find a move in the opening library
  448.   Depth = 0;
  449.   if (LibNo > 0) {
  450.     OpeningLibMsg();
  451.     InLibrary = TRUE;
  452.     FindOpeningMove();
  453.     if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
  454.      if (msg.message == WM_COMMAND && msg.wParam == CM_STOP)
  455.         return;
  456.      TranslateMessage(&msg);
  457.      DispatchMessage(&msg);
  458.     }
  459.   } else {
  460.     if (InLibrary) {
  461.       InLibrary = FALSE;
  462.       ClearMessage();
  463.     }
  464.     FindMove(MaxLevel);
  465.   }
  466.   Depth = -1;
  467.   ReturnAnalysis();
  468. }
  469.  
  470. void
  471. ProgramMove()
  472. {
  473.   do {
  474.     GotValidMove = FALSE;
  475.     ColorToPlay(Player);
  476.     StartMove();
  477.   } while (GotValidMove);
  478. }
  479.  
  480. void
  481. Talk()
  482. {
  483.   StartUp();
  484.   NewGame();
  485. }
  486.  
  487. BOOL
  488. Redo()
  489. {
  490. //   MakeMove(&MovTab[Depth+1]);
  491.   EnterMove(&MovTab[Depth+1]);
  492.   ClearHint();
  493. //   UpdateBoard();
  494.   ClearBestLine();
  495.   ColorToPlay(Player);
  496.   if (Depth >= -1)
  497.     return FALSE;  // cannot redo again
  498.   return TRUE;     // can redo again
  499. }
  500.  
  501. BOOL
  502. Undo()
  503. {
  504. // TakeBackMove(&MovTab[Depth]);
  505.   extern void RemoveMove(MOVETYPE *);
  506.   RemoveMove(&MovTab[Depth]);
  507.   ClearHint();
  508. //   UpdateBoard();
  509.   ClearBestLine();
  510.   ColorToPlay(Player);
  511.   if (MovTab[Depth].movpiece == empty)
  512.     return FALSE;  // Can't undo anymore
  513.   return TRUE;     // Can still undo
  514. }
  515.  
  516. void
  517. QuitProgram()
  518. {
  519.   if (Logging)
  520.     OutputFile->close();
  521.  
  522.   sprintf(buf, "%ld", (DWORD)WhiteSquareColor);
  523.   WritePrivateProfileString("WCHESS", "WhiteSquare", buf, INIFile);
  524.  
  525.   sprintf(buf, "%ld", (DWORD)BlackSquareColor);
  526.   WritePrivateProfileString("WCHESS", "BlackSquare", buf, INIFile);
  527.  
  528.   sprintf(buf, "%d", Level);
  529.   WritePrivateProfileString("WCHESS", "Level", buf, INIFile);
  530.   sprintf(buf, "%lf", AverageTime);
  531.   WritePrivateProfileString("WCHESS", "AverageTime", buf, INIFile);
  532.   sprintf(buf, "%d", (int)MaxLevel);
  533.   WritePrivateProfileString("WCHESS", "MaxLevel", buf, INIFile);
  534.   sprintf(buf, "%d", (int)SoundOn);
  535.   WritePrivateProfileString("WCHESS", "SoundOn", buf, INIFile);
  536. }
  537.  
  538. void
  539. FindHintMove()
  540. {
  541.   //  If hintline is empty the get the move from the
  542.   //  opening library or perform a 1 - ply search
  543.   //
  544.   if (HintLine[0].movpiece == empty) {
  545.     AdjustMoves();
  546.     CalcLibNo();
  547.     Depth = 0;
  548.     if (LibNo > 0)
  549.       FindOpeningMove();
  550.     else {
  551.       Analysis = 1;
  552.       Opan = 0;
  553.       FindMove(1);
  554.     }
  555.     Depth = -1;
  556.     HintLine[0] = MainLine[0];
  557.     HintLine[1] = ZeroMove;
  558.     HintEvalu = -MainEvalu;
  559.   }
  560. }
  561.